Skip to content

[23기_최우혁] 성능최적화 미션 제출합니다.#67

Open
whc9999 wants to merge 58 commits into
CEOS-Developers:whc9999from
whc9999:main
Open

[23기_최우혁] 성능최적화 미션 제출합니다.#67
whc9999 wants to merge 58 commits into
CEOS-Developers:whc9999from
whc9999:main

Conversation

@whc9999

@whc9999 whc9999 commented May 22, 2026

Copy link
Copy Markdown

No description provided.

whc9999 and others added 30 commits March 19, 2026 18:55
- 도메인별(User, Movie, Cinema, Reservation 등) 패키지 분리 및 엔티티 생성
- 테이블 간 연관관계 매핑 (1:N, N:1) 및 DB 제약조건(nullable, length, unique 등) 설정
- 공통 생성/수정 시간 관리를 위한 BaseTimeEntity 상속 적용
- 타입 및 상태 관리를 위한 Enum 클래스 분리 및 @Enumerated(EnumType.STRING) 적용
- BaseTimeEntity에 AuditingEntityListener 적용 및 추상 클래스(abstract)로 변경
- Application 클래스에 @EnableJpaAuditing 추가하여 생성/수정 시간 자동 감지 활성화
- Inventory 엔티티의 stockQuantity 필드 타입을 int로 변경 (수량 계산 및 검증 목적)
- Cinetalk 엔티티에 BaseTimeEntity 상속 추가
- Review 엔티티의 like_count를 카멜 케이스(likeCount)로 수정
- UserStatic 엔티티의 테이블명을 스네이크 케이스(user_statics)로 수정
- User, Movie, Cinema, Reservation 등 전 도메인에 대한 Repository 패키지 및 인터페이스 추가
- JpaRepository 상속을 통한 엔티티의 기본 CRUD(생성, 조회, 수정, 삭제) 기능 자동화 적용
- 핵심 비즈니스 로직을 위한 커스텀 쿼리 메서드(Query Method) 작성 (findByEmail, existsByNickname, findAllByOrderBySalesRateDesc, findBySaleNumber 등)
- UserService: 닉네임 중복 검증을 포함한 회원 가입 및 단건 조회 기능 추가
- MovieService: 전체 무비차트, 현재 상영작, 상영 예정작을 날짜 기준으로 분류하고 예매율 순으로 조회하는 로직 구현
- ReservationService: 상영관 타입(일반/특별관) 및 조조 여부에 따른 동적 요금 계산, 쿠폰 할인(최소 결제액 0원 방어) 적용, 예매 취소 로직(권한 검증 및 Dirty Checking) 구현
- CinemaService: 전체 지점(Cinema) 목록 및 특정 지점의 소속 상영관(Theater) 목록 조회 기능 추가
- 모든 서비스 메서드에 @transactional(readOnly = true)를 기본으로 적용하고, CUD 작업에만 @transactional을 명시하여 성능 최적화 적용
- 클라이언트-서버 간 데이터 전송을 위한 DTO (MovieCreateRequest, MovieResponse) 생성
- MovieService에 영화 생성(createMovie), 전체 조회(getAllMovies), 삭제(deleteMovie) 로직 추가
- MovieController에 4가지 기본 HTTP Method (POST, GET, GET 단건, DELETE) API 엔드포인트 구현
- 컨트롤러에 Swagger 어노테이션(@tag, @operation)을 적용하여 API 명세서 자동화
- 영화관 및 상영관 생성을 위한 Request DTO (CinemaCreateRequest, TheaterCreateRequest) 추가
- 클라이언트 응답을 위한 Response DTO (CinemaResponse, TheaterResponse) 추가
- CinemaService에 영화관 및 상영관 생성(createCinema, createTheater) 로직 추가
- CinemaController에 영화관 조회(전체/단건) 및 생성, 상영관 조회 및 생성 API 엔드포인트 구현
- Swagger(@operation)를 활용하여 Cinema API 문서화 적용
- 예매 생성을 위한 Request DTO (ReservationCreateRequest) 및 응답용 Response DTO (ReservationResponse) 추가
- ReservationController에 예매 생성(POST) 및 예매 취소(PATCH) API 엔드포인트 구현
- 클라이언트 요청 시 임시로 userId를 직접 입력받아 처리하도록 구성 (추후 Security 도입 시 변경 예정)
- Swagger(@operation)를 활용하여 예매/취소 API 명세서 자동화
- 영화/극장 선택을 생략할 수 있는(0 or 1) 게시글 작성용 Request DTO 추가
- 작성자 닉네임, 관련 영화/극장 이름 등을 포함하여 반환하는 Response DTO 구현 (Null 처리 방어 로직 포함)
- CinetalkService에 게시글 작성(createCinetalk) 및 전체 목록 조회(getAllCinetalks) 비즈니스 로직 추가
- CinetalkController에 POST 및 GET API 엔드포인트 구현 및 Swagger 문서화 적용
- 매점 상품(Product) 등록 및 전체 조회 API 구현
- 여러 개의 상품을 한 번에 주문(FoodOrder, OrderItem)하는 패스트오더 결제 로직 구현
- 특정 유저의 주문 내역을 확인하는 조회 API 추가
- 관련 DTO 4종(ProductCreateRequest, ProductResponse, FoodOrderRequest, FoodOrderResponse) 추가
- Swagger(@operation)를 활용하여 매점 API 명세서 자동화
- 관람평 생성을 위한 Request DTO 및 조회 응답용 Response DTO 추가
- ReviewRepository에 특정 영화의 리뷰만 모아보는 커스텀 쿼리 메서드(findByMovieId) 추가
- ReviewService에 관람평 작성 및 특정 영화 관람평 조회 로직 구현
- ReviewController에 POST 및 GET API 엔드포인트 구현
- Swagger(@operation)를 활용하여 리뷰 API 명세서 자동화
- 상영 일정 생성을 위한 Request DTO 및 조회 응답용 Response DTO 추가
- ScreeningRepository에 특정 영화의 상영 일정을 조회하는 커스텀 쿼리 메서드(findByMovieId) 추가
- ScreeningService에 상영 일정 등록 및 특정 영화 시간표 조회 로직 구현
- ScreeningController에 POST 및 GET API 엔드포인트 구현
- Swagger(@operation)를 활용하여 상영 일정 API 명세서 자동화
- 배우, 감독 등 인물 생성을 위한 Request/Response DTO 구현
- 인물과 영화를 N:M 관계로 연결하는 참여 정보(WorkParticipation) 등록 기능 추가
- 특정 영화의 출연진/감독 목록 조회 API 구현
- 특정 인물의 필모그래피(참여 영화 목록) 조회 API 및 커스텀 쿼리(findByPersonId) 구현
- Swagger(@operation)를 활용하여 인물 API 명세서 자동화
- 이벤트 생성(POST) 및 전체 이벤트 조회(GET) API 구현
- 특정 이벤트를 특정 영화와 연결(N:M)하는 매핑 API 추가
- MovieEventRepository에 특정 영화의 연관 이벤트만 조회하는 커스텀 쿼리 추가
- 관련 DTO(EventCreateRequest, EventResponse) 구현
- Swagger(@operation)를 활용하여 이벤트 API 명세서 자동화
- 영화 좋아요(MovieLike) 및 극장 좋아요(CinemaLike) 토글(Toggle) 기능 구현 (생성 및 취소)
- 특정 유저가 찜한 영화 및 자주 가는 극장 목록 조회 API 추가
- Repository에 유저 ID와 도메인 ID 기반으로 기존 내역을 확인하는 커스텀 쿼리 추가 (findByUserIdAndMovieId 등)
- 클라이언트 응답을 위한 DTO(MovieLikeResponse, CinemaLikeResponse) 구현
- Swagger(@operation)를 활용하여 좋아요 API 명세서 자동화 적용
- 영화(포스터/스틸컷) 및 인물(배우/감독 프로필) 사진 등록을 위한 통합 Request DTO 구현
- 사진 조회 시 연관된 영화 ID 또는 인물 ID를 유연하게 반환하는 Response DTO 추가
- PhotoRepository에 특정 영화(findByMovieId) 및 특정 인물(findByPersonId)의 사진 목록 조회 커스텀 쿼리 추가
- PhotoService 및 Controller에 사진 등록(POST) 및 도메인별 사진 조회(GET) API 엔드포인트 구현
- Swagger(@operation)를 활용하여 사진 API 명세서 자동화 적용
- 예매 시 좌석의 행(seatRow)과 열(seatCol)을 리스트 형태로 묶어서 저장하는 API 구현
- 특정 상영 일정의 이미 예매 완료된 좌석 목록 조회 기능 추가
- Entity의 @UniqueConstraint를 활용하여 DataIntegrityViolationException 캐치를 통한 중복 예매 완벽 차단 로직 구현
- 극장 지점별 매점 상품 재고를 업데이트(입고/차감)하고 조회하기 위한 API 구현
- InventoryUpdateRequest 및 InventoryResponse DTO 생성 (stockQuantity 필드명 일치)
- Entity의 @min(value = 1) 제약 조건에 맞춰, 재고가 1 미만으로 떨어지지 않도록 Service 계층에 방어 로직(IllegalStateException) 추가
- InventoryRepository에 특정 지점의 재고 목록을 조회하는 커스텀 쿼리(findByCinemaId) 추가
- Swagger(@operation)를 활용하여 재고 API 명세서 자동화 적용
- 극장 지점별 매점 상품 재고를 업데이트(입고/차감)하고 조회하기 위한 API 구현
- InventoryUpdateRequest 및 InventoryResponse DTO 생성
- Entity의 @min(value = 1) 제약 조건에 맞춰, 재고가 1 미만으로 떨어지지 않도록 Service 계층에 방어 로직(IllegalStateException) 추가
- InventoryRepository에 특정 지점의 재고 목록을 조회하는 커스텀 쿼리(findByCinemaId) 추가
- Swagger(@operation)를 활용하여 재고 API 명세서 자동화 적용
- [Cinema] 모든 지점이 특별/일반관을 가지므로 불필요한 isSpecial 필드 제거
- [Theater] 직사각형 좌석 배열 기획(중간 빈 곳 없음)을 반영하기 위해 총 좌석 수(seatCount) 대신 최대 행(maxRow)과 최대 열(maxCol) 필드로 변경
- 관련 DTO(CreateRequest, Response) 및 Service, Controller 로직 일괄 수정
- [Cinema] 모든 지점이 특별/일반관을 가지므로 불필요한 isSpecial 필드 제거
- [Theater] 직사각형 좌석 배열 기획(중간 빈 곳 없음)을 반영하기 위해 총 좌석 수(seatCount) 대신 최대 행(maxRow)과 최대 열(maxCol) 필드로 변경
- 관련 DTO(CreateRequest, Response) 및 Service, Controller 로직 일괄 수정
- 데이터 불변성(Immutability) 확보 및 Lombok 보일러플레이트 코드 제거를 위해 모든 Request/Response DTO를 Java `record` 타입으로 전면 리팩토링
- Response DTO 내부에 Entity를 받아 DTO로 변환하는 정적 팩토리 메서드(from) 패턴 일괄 적용하여 객체 생성 책임 캡슐화
- 중첩된 리스트 형태의 데이터(FoodOrderRequest, ReservedSeatRequest 등)를 내부 record로 선언하여 클래스 구조 단순화 및 가독성 개선
- record 필드 접근 규칙(get- 접두사 제거)에 맞춰 전역 Controller 및 Service 계층의 DTO 데이터 호출부 일괄 수정
- Global Exception Handling 아키텍처 도입에 따른 Service 계층 전면 리팩토링
- ErrorCode.java 내에 Person, Event, Photo 등 누락된 전체 도메인의 에러 코드(HTTP Status 포함) 명세 완비
- Service 로직 내에서 기본 발생하던 IllegalArgumentException 및 IllegalStateException을 CustomException으로 교체
- DB 조회 실패(404 Not Found) 및 비즈니스 상태 위반(Conflict, Bad Request) 시 통일된 ErrorResponse 반환 구조 확립
- ReservedSeatServiceTest
  - 이미 예약된 좌석 선택 시 SEAT_ALREADY_RESERVED 예외 검증

- InventoryServiceTest
  - 재고 부족 시 INVENTORY_SHORTAGE 예외 검증

- ConcessionServiceTest
  - 상품 주문 시 총액 계산 로직 검증

- ReviewServiceTest, MovieServiceTest
  - 기본 CRUD 및 비즈니스 로직 테스트 추가

- ReservationServiceTest
  - 예약 생성 및 예외 처리 검증

- CineTalkServiceTest
  - 게시글/댓글 관련 로직 테스트 추가
Updated image format and added a link to ERDCloud.
[23기_최우혁] cgv 미션 제출합니다.
- [Movie] 상영 일정(Screening)의 시작/종료 시간 타입을 Date에서 Time까지 포함하는 `LocalDateTime`으로 변경
- [Concession] FoodOrder(총액) 및 Inventory(재고 수정) 업데이트 시 불필요한 엔티티 병합(Merge)을 제거하고, 엔티티 내부 비즈니스 메서드를 통한 JPA 더티 체킹(Dirty Checking) 적용
- [Concession] 매점 결제 로직에 해당 지점 상품의 재고(Inventory)를 실제로 차감하는 비즈니스 로직 추가
- [Cinema] 상영관(Theater) 생성 API에서 `cinemaId`를 RequestBody에서 제거하고 PathVariable로 받도록 RESTful API 설계 원칙 적용
- [Cinema] 메서드 시그니처 축소 및 유지보수성 향상을 위해 Controller-Service 간 데이터 전달 시 개별 파라미터 대신 DTO 통째로 전달하도록 개선
- [Reservation] 예매 취소 로직 실행 시, 다른 유저의 예매를 막는 크리티컬 버그를 방지하기 위해 연관된 점유 좌석(ReservedSeat) 데이터도 함께 삭제하도록 보완
- [Test] 변경된 비즈니스 로직 및 더티 체킹 구조에 맞추어 전체 단위 테스트 코드(ServiceTest) 수정 및 불필요한 Mocking(UnnecessaryStubbing) 제거
- [Global] API 응답 통일성 및 가독성 향상을 위해 전역 공통 응답 래퍼(`ApiResponse<T>`) 도입 및 전체 컨트롤러 반환 타입 교체
- [Cinema] 극장 지역(Region) String 타입을 Enum으로 변경하여 데이터 무결성 확보 및 `@JsonCreator`로 한글 직렬화/역직렬화 지원
- [Photo] 스틸컷 등록 시 최소 1개의 대상(영화 또는 인물)이 필수 입력되도록 `record` 컴팩트 생성자를 활용한 방어 로직 추가
- [Reservation] 예매 결제 금액 계산 시 사용되던 하드코딩(매직 넘버)을 지우고, `TheaterType` Enum 내부 상태(`basePrice`)로 관리하도록 객체지향적 설계 개선
- [Reservation] `Payment` (결제 수단) Enum에 프론트엔드 노출 및 유지보수를 위한 `description` 속성 추가
- [Concession] 매점 결제(createOrder) 로직의 for문 내부 쿼리를 `findAllById`와 `saveAll`로 개선하여 다중 건 처리 성능(Bulk Insert) 최적화
- [Concession] 특정 유저의 주문 내역 조회 시 발생하는 지연 로딩(LAZY) 기반 N+1 문제를 해결하기 위해 `JOIN FETCH`를 적용한 리포지토리 메서드 추가
whc9999 and others added 28 commits March 28, 2026 15:27
- ReservationController의 cancelReservation API에서 userId를 쿼리 파라미터로 직접 받던 취약점 제거
- @AuthenticationPrincipal을 활용하여 JWT 토큰에서 안전하게 유저 식별자를 추출하도록 로직 개선
- User 엔티티에 Refresh Token 저장용 필드 및 관리 메서드 추가
- TokenProvider에 Refresh Token 생성 로직 추가
- AuthService 로그인 로직 수정: Access Token과 Refresh Token 동시 발급 및 DB 저장
- AuthController에 토큰 재발급을 위한 `/api/auth/reissue` 엔드포인트 추가
- 보안 강화를 위해 재발급 시 Refresh Token도 갱신하는 RTR(Refresh Token Rotation) 방식 적용
- JWT 개념 및 흐름, 세션/쿠키/OAuth와의 비교 내용 작성 (토글 UI 적용)
- TokenProvider 검증 로직 최적화 내용 기재
- 단방향 암호화 로그인 및 @AuthenticationPrincipal 기반 API 보안 개선 사항 정리
- RTR 기법을 적용한 Refresh Token 재발급(도전 미션) 구현 과정 명시
- 서비스 메서드의 조회, 검증, 생성, 저장 흐름 분리
- 엔티티 factory와 도메인 메서드로 생성/상태 변경 규칙 이동
- CustomException과 ErrorCode 기반으로 예외 응답 통일
- 역직렬화 중 발생한 CustomException 처리 보강
- 예약 쿠폰 할인 정책을 CouponDiscountPolicy로 분리
- 매점 주문/재고 처리 흐름과 에러 코드 의미 정리
- Gradle wrapper 복구 및 관련 테스트 보정
- README에 리팩토링 내역과 설계 의도 정리
- 예매 생성과 좌석 저장을 하나의 트랜잭션으로 통합
- Screening 조회에 PESSIMISTIC_WRITE 락 적용
- ReservedSeat 유니크 제약을 최종 중복 방어선으로 유지
- 좌석 중복 저장 시 SEAT_ALREADY_RESERVED 예외로 변환
- 동시성 해결 방법과 선택 근거를 README에 정리
- CEOS 외부 결제 서버 RestClient 연동 추가
- 예매 결제에 티켓팅 케이스 적용
- 매점 주문 결제에 커머스 케이스 적용
- 결제 실패 및 재고 부족 시 보상 처리 추가
- 결제 상태 관리를 위한 예약/매점 주문 상태 확장
- 결제 연동 설계와 테스트 결과 README 정리
- 매점 상품, 재고, 상영 일정, 영화관/상영관 관리 API를 admin 경로로 이동
- 인물, 사진, 이벤트 생성 및 연결 API를 admin 경로로 이동
- 일반 사용자 컨트롤러에는 조회, 구매, 사용자 활동 API만 유지
- 좌석 선점 API 제거 및 좌석 조회 API만 유지
- 기존 /api/admin/** 보안 규칙으로 관리자 권한 제어 적용
- JWT 검증 실패 warn 로그 추가
- 인증/인가 실패 응답을 공통 JSON 형식으로 통일
- JWT credential null 처리 및 Authorization 문자열 상수화
- 회원가입 이메일 중복 확인을 existsByEmail로 개선
- 로그인/회원가입 요청 validation 추가
- JWT secret 환경변수 분리
- 예매 가격 계산 정책 분리
- refresh token HttpOnly Cookie 전환
[23기_최우혁] deploy 미션 제출합니다.
- Spring Cache와 Caffeine을 적용해 영화, 극장, 매점 상품, 이벤트 조회 성능 개선
- Look-Aside 및 Write Around + Cache Evict 전략으로 조회 캐시와 데이터 변경 흐름 분리
- 요청 단위 로깅 필터를 추가해 method, uri, status, durationMs, requestId 기록
- Logback 파일 로그 설정 및 requestId MDC 패턴 추가
- Loki, Alloy, Grafana 기반 로컬 모니터링 스택 구성
- Grafana 대시보드용 요청 수, 5xx 오류, 결제 보상 실패 로그 쿼리 정리
- 캐시 성능 테스트 추가 및 README에 7주차 미션 내용 정리
[Feat] 캐싱 및 로깅 기반 모니터링 구현
# Conflicts:
#	README.md
- 영화 목록, 상영 일정, 매점 주문/재고, 영화 이벤트 조회에 인덱스 추가
- Aiven MySQL EXPLAIN 결과를 README에 정리
- 인덱스 적용 전후 실행 계획 비교 스크린샷 추가
- 트랜잭션 전파 속성과 현재 예매/결제 트랜잭션 구조 분석 정리
[Feat] 데이터베이스 인덱스 기반 조회 성능 최적화

@shinae1023 shinae1023 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그동안 과제하느라 수고 많으셨습니다 ㅜㅜ
세오스 끝나지망~~

Comment thread README.md

### EXPLAIN 비교 결과

실제 Aiven MySQL에 인덱스를 생성한 뒤 DataGrip에서 `EXPLAIN` 결과를 비교했다. 외래키 컬럼으로 시작하는 인덱스는 MySQL이 외래키 검사용 인덱스로도 사용하기 때문에 `DROP INDEX`가 제한되었다. 그래서 실제 인덱스를 삭제하지 않고 `IGNORE INDEX`와 `USE INDEX`로 인덱스 사용 전/후 실행 계획을 비교했다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 이부분은 몰랏는데 인덱스 적용후에도 이렇게 비교할 수 있네여 👍🏻

Comment thread README.md
| 인덱스 미사용 | `ALL` | `null` | `Using where` | 전체 주문 테이블을 스캔한 뒤 조건 필터링 |
| 인덱스 사용 | `ref` | `idx_food_orders_user_status` | `Using index condition` | `user_id`, `status` 복합 인덱스로 대상 주문 탐색 |

![food_orders 인덱스 미사용](assets/week8-db-optimization/food-orders-before.png)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

비교 결과까지 사진으로 남겨주셔서 이해하기 편했습니다

Comment thread README.md

## 6. 한계와 보완점

- 이번 적용은 JPA 엔티티의 인덱스 메타데이터 추가 방식이다. 운영 DB에서 `ddl-auto`를 사용하지 않는다면 별도 마이그레이션 SQL이 필요하다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

한계와 보완점까지 남겨주셔서 어떤 부분을 개선할 수 있는지 저도 더 찾아봐야겠다는 생각이 들었어요!
별도 마이그레이션은 한 번 저희 프로젝트에 적용해봅시다 ^.^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants